package com.mach.platform.utils.springdata;

import com.google.common.base.Splitter;
import com.google.common.collect.Lists;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.jpa.domain.Specification;

import javax.persistence.criteria.Path;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;


/**
  * @Description: 构建springData 的查询条件
  *
  * @date  2018/4/23 0023   12:47
  * @author Administrator
  */
public class DynamicSpecifications {

	public static <T> Specification<T> bySearchFilter (final Collection<SearchFilter> filters,
			final Class<T> entityClazz) {
		return (Specification<T>) (root, query, builder) -> {

			if (Collections3.isNotEmpty(filters)) {

				List<Predicate> predicates = Lists.newArrayList();
				for (SearchFilter filter : filters) {
					// nested path translate, 如Task的名为"user.name"的filedName, 转换为Task.user.name属性

					String[] names = StringUtils.split(filter.fieldName, ".");

					String[] propertiesNames = StringUtils.split(filter.fieldName, "_");

					Path expression = null;
					if (names.length > 0 && propertiesNames.length == 1) {
						expression = root.get(names[0]);
						for (int i = 1; i < names.length; i++) {
							expression = expression.get(names[i]);
						}
					}

					// logic operator
					switch (filter.operator) {
						case EQ:
							predicates.add(builder.equal(expression, filter.value));
							break;
						case NIN:
							// not in (i i )  必须传入 集合，而不是数组
							//interface Expression<T>  接口 有 in 的拼接: javax\persistence\criteria\Expression.java

							Long[] arrs = turnTheStringToArrays(filter.value.toString());
							predicates.add(builder.not(expression.in(Arrays.asList(arrs))));

							break;
						case LIKE:
							predicates.add(builder.like(expression, "%" + filter.value + "%"));
							break;
						case PLIKE:
							// 多个字段属性 like 一个值
							//如：realName_mobile_userName_education_major_nativePlace_plike
							String[] res = filter.fieldName.split("_");

							System.out.println(Arrays.asList(res));

							Predicate[] likes = new Predicate[res.length];
							for (int i = 0; i < res.length; i++) {

								if (res[i].indexOf(".") == -1) {
									Path expressionForLike = root.get(res[i]);
									likes[i] = builder.like(builder.upper(expressionForLike),"%" + filter.value.toString() + "%");
								}else {

									List<String> stringList = Splitter.on(".").splitToList(res[i]);

									Path innerexpression = root.get(stringList.get(0));
									for (int k = 1; k< stringList.size(); k++) {
										innerexpression = innerexpression.get(stringList.get(k));
									}

									likes[i] = builder.like(innerexpression, "%" + filter.value.toString() + "%");

								}

							}
							predicates.add(builder.or(likes));

							break;
						case VLIKE:
							predicates.add(builder.like(expression, "%" + filter.value + "%"));
							break;
						case GT:
							predicates.add(builder.greaterThan(expression, (Comparable) filter.value));
							break;
						case LT:
							predicates.add(builder.lessThan(expression, (Comparable) filter.value));
							break;
						case GTE:
							predicates.add(builder.greaterThanOrEqualTo(expression, (Comparable) filter.value));
							break;
						case LTE:
							predicates.add(builder.lessThanOrEqualTo(expression, (Comparable) filter.value));
							break;
						case NN:
							//is not null
							predicates.add(builder.isNotNull(expression));
							break;
						default:
							break;

					}
				}

				// 将所有条件用 and 联合起来
				if (!predicates.isEmpty()) {
					return builder.and(predicates.toArray(new Predicate[predicates.size()]));
				}
			}

			return builder.conjunction();
		};
	}

	/**
	 * 把字符串转为 数组
	 *
	 * @param ids
	 * @return
	 */
	public static Long[] turnTheStringToArrays (String ids) {

		String[] idss = ids.split(",");

		List<Long> result = new ArrayList<>();

		for (int i = 0; i < idss.length; i++) {

			if (idss[i].equals("")) {
				continue;
			}
			Long tempId = Long.parseLong(idss[i]);
			//去重
			if (!result.contains(tempId)) {
				result.add(tempId);
			}
		}

		return result.toArray(new Long[result.size()]);
	}
}
